﻿using static FolderCompare.Properties.Resources;
using MessageBox = CgdataBase.Views.MessageBox;

namespace FolderCompare.ViewModels;

public class MainWindowViewModel : BindableBase, IBusyScope
{
    private readonly IAppSettings _settings;
    private readonly IDataHelper _helper;
    private readonly IContainerProvider _container;
    private readonly IEventAggregator _aggregator;
    public int FontSize => _settings.FontSize;
    public string FontName => _settings.FontName;

    public string Title { get; set; }
    public bool Topmost { get; set; }
    public string[] TextFileTypes { get; set; }

    public bool IsBusy { get; set; }
    public string? BusyContent { get; set; }
    public ConcurrentStack<bool> BusyStack { get; set; } = new ConcurrentStack<bool>();

    public HeaderInfo CurrentHeader => StackItems.Last();
    public ObservableCollection<HeaderInfo> StackItems { get; set; } = default!;

    public ObservableCollection<string>? LeftRootItems { get; set; }
    public string? LeftRootPath { get; set; }
    public CgDirectoryInfo? LeftRoot { get; set; }

    public ObservableCollection<string> RightRootItems { get; set; }
    public string? RightRootPath { get; set; }
    public CgDirectoryInfo? RightRoot { get; set; }

    private CgDirectoryInfo? _currentLeft;
    private CgDirectoryInfo? _currentRight;

    public ObservableCollection<CgFileSystemInfo>? LeftItems { get; set; }
    public CgFileSystemInfo? SelectedLeft { get; set; }
    public ObservableCollection<CgFileSystemInfo>? RightItems { get; set; }
    public CgFileSystemInfo? SelectedRight { get; set; }
    public int SelectedIndex { get; set; } = -1;

    public IEnumerable? SelectedLefts { get; set; }
    public IEnumerable? SelectedRights { get; set; }

    public EShowType ShowType { get; set; }

    public DelegateCommand BackUpCommand { get; private set; }

    public DelegateCommand SelectLeftRootCommand { get; }
    public DelegateCommand SelectRightRootCommand { get; }

    public DelegateCommand OpenFolderLeftCommand { get; }
    public DelegateCommand CopyToRightCommand { get; }
    public DelegateCommand MoveToRightCommand { get; }
    public DelegateCommand CopyNameLeftCommand { get; }
    public DelegateCommand CopyFullNameLeftCommand { get; }
    public DelegateCommand DeleteLeftCommand { get; }
    public DelegateCommand ExportLeftCommand { get; }
    public DelegateCommand RefreshLeftCommand { get; }

    public DelegateCommand OpenFolderRightCommand { get; }
    public DelegateCommand CopyToLeftCommand { get; }
    public DelegateCommand MoveToLeftCommand { get; }
    public DelegateCommand CopyNameRightCommand { get; }
    public DelegateCommand CopyFullNameRightCommand { get; }
    public DelegateCommand DeleteRightCommand { get; }
    public DelegateCommand ExportRightCommand { get; }
    public DelegateCommand RefreshRightCommand { get; }
    public DelegateCommand RefreshCommand { get; }

    public DelegateCommand ShowAllCommand { get; }
    public DelegateCommand ShowNotEqualCommand { get; }
    public DelegateCommand ShowEqualsCommand { get; }

    public DelegateCommand<MouseButtonEventArgs> LeftDoubleClickCommand { get; }
    public DelegateCommand<MouseButtonEventArgs> RightDoubleClickCommand { get; }
    public DelegateCommand<DragEventArgs> LeftDropCommand { get; private set; }
    public DelegateCommand<DragEventArgs> RightDropCommand { get; private set; }

    public DelegateCommand LoadedCommand { get; }
    public DelegateCommand<CancelEventArgs> ClosingCommand { get; private set; }
    public DelegateCommand AboutCommand { get; }
    public DelegateCommand SettingsCommand { get; }
    public DelegateCommand QuitCommand { get; }

    public MainWindowViewModel(IAppSettings settings, 
        IDataHelper helper, 
        IContainerProvider container, 
        IEventAggregator aggregator)
    {
        _settings = settings;
        _helper = helper;
        _container = container;
        _aggregator = aggregator;

        Title = ApplicationName;
        TextFileTypes = GetTextFileTypes();

        LeftRootItems = GetLeftRootItems().ToObservableCollection();
        RightRootItems = GetRightRootItems().ToObservableCollection();

        SelectLeftRootCommand = new DelegateCommand(OnSelectLeftRoot);
        SelectRightRootCommand = new DelegateCommand(OnSelectRightRoot);

        OpenFolderLeftCommand = new DelegateCommand(OnOpenFolderLeft, CanEditLeft).ObservesProperty(() => SelectedLeft);
        CopyToRightCommand = new DelegateCommand(OnCopyToRight, CanEditLeft).ObservesProperty(() => SelectedLeft);
        MoveToRightCommand = new DelegateCommand(OnMoveToRight, CanEditLeft).ObservesProperty(() => SelectedLeft);
        ExportLeftCommand = new DelegateCommand(OnExportLeft, CanEditLeft).ObservesProperty(() => SelectedLeft);
        CopyNameLeftCommand = new DelegateCommand(OnCopyNameLeft, CanEditLeft).ObservesProperty(() => SelectedLeft);
        CopyFullNameLeftCommand = new DelegateCommand(OnCopyFullNameLeft, CanEditLeft).ObservesProperty(() => SelectedLeft);

        DeleteLeftCommand = new DelegateCommand(OnDeleteLeft, CanEditLeft).ObservesProperty(() => SelectedLeft);
        RefreshLeftCommand = new DelegateCommand(OnRefreshLeft);

        OpenFolderRightCommand = new DelegateCommand(OnOpenFolderRight, CanEditRight).ObservesProperty(() => SelectedLeft);
        CopyToLeftCommand = new DelegateCommand(OnCopyToLeft, CanEditRight).ObservesProperty(() => SelectedLeft);
        MoveToLeftCommand = new DelegateCommand(OnMoveToLeft, CanEditRight).ObservesProperty(() => SelectedLeft);
        ExportRightCommand = new DelegateCommand(OnExportRight, CanEditRight).ObservesProperty(() => SelectedLeft);
        CopyNameRightCommand = new DelegateCommand(OnCopyNameRight, CanEditRight).ObservesProperty(() => SelectedLeft);
        CopyFullNameRightCommand = new DelegateCommand(OnCopyFullNameRight, CanEditRight).ObservesProperty(() => SelectedLeft);

        DeleteRightCommand = new DelegateCommand(OnDeleteRight, CanEditRight).ObservesProperty(() => SelectedRight);
        RefreshRightCommand = new DelegateCommand(OnRefreshRight);
        RefreshCommand = new DelegateCommand(OnRefresh);

        ShowAllCommand = new DelegateCommand(OnShowAll);
        ShowNotEqualCommand = new DelegateCommand(OnShowNotEqual);
        ShowEqualsCommand = new DelegateCommand(OnShowEquals);

        LoadedCommand = new DelegateCommand(OnLoaded);
        ClosingCommand = new DelegateCommand<CancelEventArgs>(OnClosing);

        BackUpCommand = new DelegateCommand(OnBackUp);
        QuitCommand = new DelegateCommand(OnQuit);

        LeftDoubleClickCommand = new DelegateCommand<MouseButtonEventArgs>(OnLeftDoubleClick);
        RightDoubleClickCommand = new DelegateCommand<MouseButtonEventArgs>(OnRightDoubleClick);

        LeftDropCommand = new DelegateCommand<DragEventArgs>(OnLeftDrop);
        RightDropCommand = new DelegateCommand<DragEventArgs>(OnRightDrop);

        AboutCommand = new DelegateCommand(OnAbout);
        SettingsCommand = new DelegateCommand(OnSettings);

        _aggregator.GetEvent<SwitchHeaderEvent>().Subscribe(OnSwitchHeader, ThreadOption.UIThread);
    }

    private void OnQuit()
    {
        App.Current.Shutdown();
    }

    private void SaveRightRootItems(string path)
    {
        if (RightRootItems.Contains(path) == true)
            return;

        RightRootItems.Add(path);
        File.WriteAllLines(GetFileNameRight(), RightRootItems);
    }

    private void SaveLeftRootItems(string path)
    {
        if (LeftRootItems.Contains(path) == true)
            return;

        LeftRootItems.Add(path);
        File.WriteAllLines(GetFileNameLeft(), LeftRootItems);
    }

    private string[] GetRightRootItems()
    {
        return AppBase.ReadAllLines(GetFileNameRight());
    }

    private string[] GetLeftRootItems()
    {
        return AppBase.ReadAllLines(GetFileNameLeft());
    }

    private string GetFileNameRight()
    {
        return FileSystemHelper.GetFullPath("RightRootItems.txt");
    }

    private string GetFileNameLeft()
    {
        return FileSystemHelper.GetFullPath("LeftRootItems.txt");
    }

    private string[] GetTextFileTypes()
    {
        return _settings.TextFileTypes.StringSplit("\r\n");
    }

    private void OnOpenFolderRight()
    {
        Process.Start("explorer.exe", "/select," + SelectedRight!.FullName);
    }

    private void OnOpenFolderLeft()
    {
        Process.Start("explorer.exe", "/select," + SelectedLeft!.FullName);
    }

    private async void OnCopyToLeft()
    {
        if (_currentRight == null)
        {
            MessageBox.Show("左侧路径不存在");
            return;
        }
        GuardHelper.NotNull(SelectedRights);
        var items = SelectedRights.Cast<CgFileSystemInfo>().ToArray();
        var message = $"是否把选中的 {items.Length} 项复制到左侧？";
        if (MessageBox.Show(message, "提示", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
        {
            using var scope = new BusyScope(this);
            var dirPath = _currentLeft.FullName;
            var cts = new CancellationTokenSource();
            await Task.Run(() =>
            {
                foreach (CgFileSystemInfo item in items)
                {
                    if (item is CgFileInfo file)
                    {
                        File.Copy(file.FullName, Path.Combine(dirPath, file.Name), true);
                    }
                    else if (item is CgDirectoryInfo dir)
                    {
                        var targetPath = Path.Combine(dirPath, dir.Name);
                        if (Directory.Exists(targetPath))
                        {
                            Directory.Delete(targetPath, true);
                        }

                        FileSystemHelper.CopyFolder(dir.FullName, targetPath, cts.Token);
                    }
                }
            });

            OnRefresh();
        }
    }

    private async void OnMoveToLeft()
    {
        if (_currentRight == null)
        {
            MessageBox.Show("左侧路径不存在");
            return;
        }

        var items = SelectedRights!.Cast<CgFileSystemInfo>().ToArray();
        var message = $"是否把选中的 {items.Length} 项移动到左侧？";
        if (MessageBox.Show(message, "提示", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
        {
            using (var scope = new BusyScope(this))
            {
                var dirPath = _currentLeft.FullName;
                var cts = new CancellationTokenSource();
                await Task.Run(() =>
                {
                    foreach (CgFileSystemInfo item in items)
                    {
                        if (item is CgFileInfo file)
                        {
                            File.Move(file.FullName, Path.Combine(dirPath, file.Name), true);
                        }
                        else if (item is CgDirectoryInfo dir)
                        {
                            var targetPath = Path.Combine(dirPath, dir.Name);
                            if (Directory.Exists(targetPath))
                            {
                                Directory.Delete(targetPath, true);
                            }
                            Directory.Move(dir.FullName, targetPath);
                        }
                    }
                });

                OnRefresh();
            }
        }
    }

    private async void OnCopyToRight()
    {
        if (_currentRight == null)
        {
            MessageBox.Show("右侧路径不存在");
            return;
        }

        var items = SelectedLefts!.Cast<CgFileSystemInfo>().ToArray();
        var message = $"是否把选中的 {items.Length} 项复制到右侧？";
        if (MessageBox.Show(message, "提示", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
        {
            using (var scope = new BusyScope(this))
            {
                var dirPath = _currentRight.FullName;
                var cts = new CancellationTokenSource();
                await Task.Run(() =>
                {
                    foreach (CgFileSystemInfo item in items)
                    {
                        if (item is CgFileInfo file)
                        {
                            File.Copy(file.FullName, Path.Combine(dirPath, file.Name), true);
                        }
                        else if (item is CgDirectoryInfo dir)
                        {
                            var targetPath = Path.Combine(dirPath, dir.Name);
                            if (Directory.Exists(targetPath))
                            {
                                Directory.Delete(targetPath, true);
                            }

                            FileSystemHelper.CopyFolder(dir.FullName, targetPath, cts.Token);
                        }
                    }
                });
            }

            OnRefresh();
        }
    }

    private async void OnMoveToRight()
    {
        if (_currentRight == null)
        {
            MessageBox.Show("右侧路径不存在");
            return;
        }

        var items = SelectedLefts!.Cast<CgFileSystemInfo>().ToArray();
        var message = $"是否把选中的 {items.Length} 项移动到右侧？";
        if (MessageBox.Show(message, "提示", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
        {
            using (var scope = new BusyScope(this))
            {
                var dirPath = _currentRight.FullName;
                var cts = new CancellationTokenSource();
                await Task.Run(() =>
                {
                    foreach (CgFileSystemInfo item in items)
                    {
                        if (item is CgFileInfo file)
                        {
                            File.Move(file.FullName, Path.Combine(dirPath, file.Name), true);
                        }
                        else if (item is CgDirectoryInfo dir)
                        {
                            var targetPath = Path.Combine(dirPath, dir.Name);
                            if (Directory.Exists(targetPath))
                            {
                                Directory.Delete(targetPath, true);
                            }

                            Directory.Move(dir.FullName, targetPath);
                        }
                    }
                });
            }

            OnRefresh();
        }
    }

    private async void OnExportRight()
    {
        var dialog = new OpenFolderDialog();
        if (dialog.ShowDialog() == true)
        {
            var dirPath = dialog.FolderName;
            var items = SelectedRights!.Cast<CgFileSystemInfo>().ToArray();

            using (var scope = new BusyScope(this))
            {
                var cts = new CancellationTokenSource();
                await Task.Run(() =>
                {
                    foreach (CgFileSystemInfo item in items)
                    {
                        if (item is CgFileInfo file)
                        {
                            File.Copy(file.FullName, Path.Combine(dirPath, file.Name), true);
                        }
                        else if (item is CgDirectoryInfo dir)
                        {
                            FileSystemHelper.CopyFolder(dir.FullName, Path.Combine(dirPath, dir.Name), cts.Token);
                        }
                    }
                });
            }

            MessageBox.Show("导出成功");
        }
    }

    private async void OnExportLeft()
    {
        var dialog = new OpenFolderDialog();
        if (dialog.ShowDialog() == true)
        {
            var dirPath = dialog.FolderName;
            var items = SelectedLefts!.Cast<CgFileSystemInfo>().ToArray();

            using (var scope = new BusyScope(this))
            {
                var cts = new CancellationTokenSource();
                await Task.Run(() =>
                {
                    foreach (CgFileSystemInfo item in items)
                    {
                        if (item is CgFileInfo file)
                        {
                            File.Copy(file.FullName, Path.Combine(dirPath, file.Name), true);
                        }
                        else if (item is CgDirectoryInfo dir)
                        {
                            FileSystemHelper.CopyFolder(dir.FullName, Path.Combine(dirPath, dir.Name), cts.Token);
                        }
                    }
                });
            }

            MessageBox.Show("导出成功");
        }
    }

    private void OnCopyFullNameRight()
    {
        var items = SelectedRights!.Cast<CgFileSystemInfo>().ToArray();
        ClipboardEx.SetText(items.Select(s => s.FullName).StringJoin("\r\n"));
    }

    private void OnCopyNameRight()
    {
        var items = SelectedRights!.Cast<CgFileSystemInfo>().ToArray();
        ClipboardEx.SetText(items.Select(s => s.Name).StringJoin("\r\n"));
    }

    private void OnCopyFullNameLeft()
    {
        var items = SelectedLefts!.Cast<CgFileSystemInfo>().ToArray();
        ClipboardEx.SetText(items.Select(s => s.FullName).StringJoin("\r\n"));
    }

    private void OnCopyNameLeft()
    {
        var items = SelectedLefts!.Cast<CgFileSystemInfo>().ToArray();
        ClipboardEx.SetText(items.Select(s => s.Name).StringJoin("\r\n"));
    }

    private void OnRightDrop(DragEventArgs e)
    {
        var fileNames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
        var dirName = fileNames[0];
        if (Directory.Exists(dirName))
        {
            UpdateRightRootPath(dirName);
        }
    }

    private void OnLeftDrop(DragEventArgs e)
    {
        var fileNames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
        var dirName = fileNames[0];
        if (Directory.Exists(dirName))
        {
            UpdateLeftRootPath(dirName);
        }
    }

    private void OnShowAll()
    {
        ShowType = EShowType.显示全部;
        ResetLeftRightItems();
    }

    private void OnShowNotEqual()
    {
        ShowType = EShowType.显示差异项;
        ResetLeftRightItems();
    }

    private void OnShowEquals()
    {
        ShowType = EShowType.显示相同项;
        ResetLeftRightItems();
    }

    private async void OnRefresh()
    {
        using var scope = new BusyScope(this);
        await Task.Run(() =>
        {
            LoadLeftRoot();
            LoadRightRoot();
            CompareLeftRightRoot();
            ResetLeftRightItems();
        });
    }

    private void CompareLeftRightRoot()
    {
        if (LeftRoot == null || RightRoot == null)
            return;

        CompareHelper.CompareDirectory(LeftRoot, RightRoot);

        SaveLeftRootItems(LeftRootPath);
        SaveRightRootItems(RightRootPath);
    }

    private void OnClosing(CancelEventArgs e)
    {
        ObjectHelper.DeepCopy(this, _settings);
    }

    private void OnLoaded()
    {
        ObjectHelper.DeepCopy(_settings, this);
    }

    private void OnBackUp()
    {
        if (StackItems.Count > 1)
        {
            StackItems.RemoveAt(StackItems.Count - 1);
        }

        ReloadLeftRightItems();
    }

    private void OnSwitchHeader(HeaderInfo info)
    {
        while (info.Index != StackItems.Last().Index)
        {
            StackItems.RemoveAt(StackItems.Count - 1);
        }

        ReloadLeftRightItems();
    }

    private void OnLeftDoubleClick(MouseButtonEventArgs e)
    {
        var list = e.Source as ItemsControl;
        var item = UIElementHelper.GetElementFromPoint(list, e.GetPosition(list));
        if (item != null && CanEditLeft())
        {
            DoubleClickItem(SelectedLeft);
        }
    }

    private void DoubleClickItem(CgFileSystemInfo? info)
    {
        if (info is CgDirectoryInfo dir)
        {
            StackItems.Add(new HeaderInfo() { Header = dir.Name, Index = StackItems.Count });
            ReloadLeftRightItems();
        }
        else if (info is CgFileInfo file)
        {
            if (IsTextFile(file) && AllContainsFile(file.Index))
            {
                new WinTextCompare(LeftItems?.Single(s => s.Index == file.Index).FullName, RightItems?.Single(s => s.Index == file.Index).FullName) { Owner = ApplicationBase.GetActiveWindow() }.ShowDialog();
            }
            else
            {
                Process.Start(new ProcessStartInfo(file.FullName) { UseShellExecute = true });
            }
        }
        else
        {
            Debug.Assert(false);
        }
    }

    private bool AllContainsFile(int index)
    {
        return LeftItems?.SingleOrDefault(s => s.Index == index)?.FullName.IsContainValidText() == true && RightItems?.SingleOrDefault(s => s.Index == index)?.FullName.IsContainValidText() == true;
    }

    private bool IsTextFile(CgFileInfo file)
    {
        var extName = Path.GetExtension(file.FullName);

        return TextFileTypes.Contains(extName);
    }

    private bool CanEditLeft()
    {
        return SelectedLeft != null;
    }

    private void OnRightDoubleClick(MouseButtonEventArgs e)
    {
        var list = e.Source as ItemsControl;
        var item = UIElementHelper.GetElementFromPoint(list, e.GetPosition(list));
        if (item != null && CanEditRight())
        {
            DoubleClickItem(SelectedRight);
        }
    }

    private bool CanEditRight()
    {
        return SelectedRight != null;
    }

    private void ResetLeftRightItems()
    {
        StackItems = new ObservableCollection<HeaderInfo> { new HeaderInfo() { Header = "" } };

        ReloadLeftRightItems();
    }

    private void ReloadLeftRightItems()
    {
        _currentLeft = GetCurrentDirectory(LeftRoot);
        _currentRight = GetCurrentDirectory(RightRoot);

        switch (ShowType)
        {
            case EShowType.显示全部:
                LeftItems = _currentLeft?.Children;
                RightItems = _currentRight?.Children;
                break;

            case EShowType.显示差异项:
                LeftItems = _currentLeft?.Children?.Where(s => s.Result != ECompareResult.匹配).ToObservableCollection();
                RightItems = _currentRight?.Children?.Where(s => s.Result != ECompareResult.匹配).ToObservableCollection();
                break;

            case EShowType.显示相同项:
                LeftItems = _currentLeft?.Children?.Where(s => s.Result == ECompareResult.匹配).ToObservableCollection();
                RightItems = _currentRight?.Children?.Where(s => s.Result == ECompareResult.匹配).ToObservableCollection();
                break;

            default:
                break;
        }
    }

    private void OnDeleteLeft()
    {
        if (SelectedLeft == null)
            return;

        AppBase.DeleteItems(SelectedLefts!.Cast<CgFileSystemInfo>().ToArray(), _currentLeft!, _currentRight!);
        ReloadLeftRightItems();
    }

    private void OnDeleteRight()
    {
        if (SelectedRight == null)
            return;

        AppBase.DeleteItems(SelectedRights!.Cast<CgFileSystemInfo>().ToArray(), _currentRight!, _currentLeft!);
        ReloadLeftRightItems();
    }

    private void OnRefreshLeft()
    {
        LoadLeftRoot();
        RemoveEmptyItem(RightRoot);
        CompareLeftRightRoot();

        ResetLeftRightItems();
    }

    private void RemoveEmptyItem(CgDirectoryInfo? info)
    {
        if (info == null)
            return;

        if (info.Children.HadItems())
        {
            foreach (var item in info.Children.ToArray())
            {
                if (item.Name.IsNullOrEmpty())
                {
                    info.Children.Remove(item);
                }
                else
                {
                    if (item is CgDirectoryInfo dir)
                    {
                        RemoveEmptyItem(dir);
                    }
                }
            }
        }
    }

    private void LoadLeftRoot()
    {
        if (LeftRootPath.IsContainValidText() && Directory.Exists(LeftRootPath))
        {
            LeftRoot = new CgDirectoryInfo(new DirectoryInfo(LeftRootPath));
        }
    }

    private CgDirectoryInfo? GetCurrentDirectory(CgDirectoryInfo? info)
    {
        if (info == null)
        {
            return null;
        }

        for (int i = 1; i < StackItems.Count; i++)
        {
            if (info != null)
            {
                info = GetDirectoryInfo(info, StackItems[i].Header);
            }
            else
            {
                break;
            }
        }

        return info;
    }

    private CgDirectoryInfo? GetDirectoryInfo(CgDirectoryInfo info, string name)
    {
        return info.Children?.OfType<CgDirectoryInfo>().FirstOrDefault(s => s.Name == name);
    }

    private void OnRefreshRight()
    {
        LoadRightRoot();
        RemoveEmptyItem(LeftRoot);
        CompareLeftRightRoot();

        ResetLeftRightItems();
    }

    private void LoadRightRoot()
    {
        if (RightRootPath.IsContainValidText() && Directory.Exists(RightRootPath))
        {
            RightRoot = new CgDirectoryInfo(new DirectoryInfo(RightRootPath));
        }
    }

    private void OnSelectLeftRoot()
    {
        var dialog = new OpenFolderDialog();
        if (dialog.ShowDialog() == true)
        {
            UpdateLeftRootPath(dialog.FolderName);
        }
    }

    private void UpdateLeftRootPath(string path)
    {
        LeftRootPath = path;
        OnRefreshLeft();
    }

    private void OnSelectRightRoot()
    {
        var dialog = new OpenFolderDialog();
        if (dialog.ShowDialog() == true)
        {
            UpdateRightRootPath(dialog.FolderName);
        }
    }

    private void UpdateRightRootPath(string path)
    {
        RightRootPath = path;
        OnRefreshRight();
    }

    private void OnAbout()
    {
        var vm = _container.Resolve<WinAboutViewModel>();
        var win = new WinAbout() { Owner = App.Current.MainWindow, DataContext = vm };
        vm.LoadInfo(_settings, ApplicationName);
        win.ShowDialog();
    }

    private void OnSettings()
    {
        var win = new WinSettings() { Owner = App.Current.MainWindow };
        if (win.ShowDialog() == true)
        {
            RaisePropertyChanged(nameof(FontName));
            RaisePropertyChanged(nameof(FontSize));

            OnRefresh();
        }
    }
}

public enum EShowType
{
    显示全部,
    显示差异项,
    显示相同项,
}